using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Collections;

namespace ParsingLogic.BTS_MapReader
{
    public static class MapReader
    {
        internal static Hashtable GetLinksForActivity(string ActivityName, string ExistingMap)
        {
            //We look for the ActivityName in the right hand side of the BAM Map.  For example:
            //        <Link LinkID="1" LinkFrom="/*[local-name()='&lt;Schema&gt;']/*[local-name()='ShowInvoiceXML1']/*[local-name()='EAIHeader']/@*[local-name()='EAIDescriptorID']" LinkTo="/*[local-name()='&lt;Schema&gt;']/*[local-name()='Root']/*[local-name()='EAIHeader']/*[local-name()='EAIDescriptorID']" Label="" />
            //is an example of the Link from a document type of ShowInvoiceXML1 root to EAIHeader.EAIDescriptorID

            XmlDocument _existingDoc = new XmlDocument();
            _existingDoc.Load(ExistingMap);
            

             //Load the existing RootNode_Name
            XmlNodeList _nodes = _existingDoc.SelectNodes("/*[local-name()='mapsource']/*[local-name()='Pages']/*[local-name()='Page']/*[local-name()='Links']");
            Hashtable _links = new Hashtable(_nodes.Count);
            foreach (XmlNode node in _nodes)
            {
                foreach (XmlNode childNodes in node.ChildNodes)
                {
                    if (ParseDestinationParentActivity(childNodes.Attributes["LinkTo"].InnerText).ToLower() == ActivityName.ToLower())
                    {
                        _links.Add(ParseSourceLink(childNodes.Attributes["LinkFrom"].InnerText, _existingDoc), ParseDestinationParentActivity(childNodes.Attributes["LinkTo"].InnerText) + "." + ParseDestinationActivity(childNodes.Attributes["LinkTo"].InnerText));
                    }
                }
            }
            
            //Locate the map information
            //_existingDoc.SelectNodes("/*[local-name()='mapsource']/*[local-name()='SrcTree']")[0].Attributes["RootNode_Name"].InnerText = RootNode

            return _links;
        }
        internal static Hashtable GetContextAndMethodLinksForActivity(string ActivityName, string ExistingMap)
        {
            //We look for the ActivityName in the right hand side of the BAM Map.  For example:
            //        <Link LinkID="1" LinkFrom="/*[local-name()='&lt;Schema&gt;']/*[local-name()='ShowInvoiceXML1']/*[local-name()='EAIHeader']/@*[local-name()='EAIDescriptorID']" LinkTo="/*[local-name()='&lt;Schema&gt;']/*[local-name()='Root']/*[local-name()='EAIHeader']/*[local-name()='EAIDescriptorID']" Label="" />
            //is an example of the Link from a document type of ShowInvoiceXML1 root to EAIHeader.EAIDescriptorID

            XmlDocument _existingDoc = new XmlDocument();
            _existingDoc.Load(ExistingMap);


            //Load the existing RootNode_Name
            XmlNodeList _nodes = _existingDoc.SelectNodes("/*[local-name()='mapsource']/*[local-name()='Pages']/*[local-name()='Page']/*[local-name()='Links']");
            Hashtable _links = new Hashtable(_nodes.Count);
            foreach (XmlNode node in _nodes)
            {
                foreach (XmlNode childNodes in node.ChildNodes)
                {
                    if (ParseDestinationParentActivity(childNodes.Attributes["LinkTo"].InnerText).ToLower() == ActivityName.ToLower())
                    {
                        _links.Add(ParseSourceLink(childNodes.Attributes["LinkFrom"].InnerText, _existingDoc), ParseDestinationParentActivity(childNodes.Attributes["LinkTo"].InnerText) + "." + ParseDestinationActivity(childNodes.Attributes["LinkTo"].InnerText));
                    }
                }
            }

            //Locate the map information
            //_existingDoc.SelectNodes("/*[local-name()='mapsource']/*[local-name()='SrcTree']")[0].Attributes["RootNode_Name"].InnerText = RootNode

            return _links;
        }
        internal static Hashtable GetUploadLinks(string ActivityName, string ContextUploadMap)
        {
            
            XmlDocument _existingDoc = new XmlDocument();
            _existingDoc.Load(ContextUploadMap);


            //Load the existing RootNode_Name
            XmlNodeList _nodes = _existingDoc.SelectNodes("/*[local-name()='mapsource']/*[local-name()='Pages']/*[local-name()='Page']/*[local-name()='Links']");
            Hashtable _links = new Hashtable(_nodes.Count);
            foreach (XmlNode node in _nodes)
            {
                foreach (XmlNode childNodes in node.ChildNodes)
                {
                    if (ParseUploadActivityLink(childNodes.Attributes["LinkFrom"].InnerText) == ActivityName)
                    {
                        _links.Add(ParseUploadActivityLink(childNodes.Attributes["LinkTo"].InnerText),   ParseDestinationActivity(childNodes.Attributes["LinkTo"].InnerText).Split('.')[0]);
                    }
                }
            }
            return _links;
        }
        public static string SourceXSDName(string ExistingMap)
        {
            
            XmlDocument _existingDoc = new XmlDocument();
            _existingDoc.Load(ExistingMap);

                       
            //Locate the map information
            //_existingDoc.SelectNodes("/*[local-name()='mapsource']/*[local-name()='SrcTree']")[0].Attributes["RootNode_Name"].InnerText = RootNode;
            
            //The MsgName will mostlikely be the first element in the xpath string
            XmlNodeList _nodes = _existingDoc.SelectNodes("/*[local-name()='mapsource']/*[local-name()='Pages']/*[local-name()='Page']/*[local-name()='Links']");
            Hashtable _links = new Hashtable(_nodes.Count);
            string firstLink = "";
            foreach (XmlNode node in _nodes)
            {
                foreach (XmlNode childNodes in node.ChildNodes)
                {
                    firstLink = childNodes.Attributes["LinkFrom"].InnerText;
                    break;                    
                }
            }
            //Disect the first link;
            string[] firstLinkItems = firstLink.Split(']');
            //firstLink should look something like this:LinkFrom="/*[local-name()='&lt;Schema&gt;']/*[local-name()='ShowInvoiceXML1']/*[local-name()='EAIHeader']/@*[local-name()='EAIDescriptorID']"
            firstLink = firstLinkItems[1];
            //*[local-name()='ShowInvoiceXML1'
            firstLinkItems = firstLink.Split('=');

            firstLink = firstLinkItems[1].Substring(1, firstLinkItems[1].Length - 2);
            
                
            
            //use this if you want to return the XSD Document name rather than the Root Node
            //string XSDNameInMap = _existingDoc.SelectNodes("/*[local-name()='mapsource']/*[local-name()='SrcTree']/*[local-name()='Reference']")[0].Attributes["Location"].InnerText;
            //string[] _vals = XSDNameInMap.Split('\\');
            //string XSDName = _vals[_vals.Length - 1].Substring(0, _vals[_vals.Length - 1].Length - 4);

            return firstLink;
        }
        public static ArrayList GetActivityList(string ExistingMap)
        {
            ArrayList _activities = new ArrayList();
            XmlDocument _existingDoc = new XmlDocument();
            try
            {
                _existingDoc.Load(ExistingMap);
            }
            catch (System.Exception emsg)
            {
                Console.WriteLine("Could not load the Existing Map Specified.  Error:" + emsg.Message);
                //We need to exit the console application
                Environment.Exit(-1);
                //throw emsg;
            }
            


            //Load the existing RootNode_Name
            XmlNodeList _nodes = _existingDoc.SelectNodes("/*[local-name()='mapsource']/*[local-name()='Pages']/*[local-name()='Page']/*[local-name()='Links']");
            
            foreach (XmlNode node in _nodes)
            {
                foreach (XmlNode childNodes in node.ChildNodes)
                {
                    int functiodNumber = 0;
                    bool isNumber = false;
                    isNumber = System.Int32.TryParse(childNodes.Attributes["LinkTo"].InnerText,out functiodNumber);
                    if (!isNumber)
                    {
                        isNumber = System.Int32.TryParse(childNodes.Attributes["LinkFrom"].InnerText, out functiodNumber);
                        if (!isNumber)
                        {
                            //This is a string value and not a funtoid on the map
                            if (!_activities.Contains(ParseDestinationParentActivity(childNodes.Attributes["LinkTo"].InnerText)))
                            {
                                _activities.Add(ParseDestinationParentActivity(childNodes.Attributes["LinkTo"].InnerText));
                            }
                        }
                    }
                }
            }


            return _activities;
        }

        public static string ParseDestinationActivity(string LinkTo)
        {
            if (LinkTo.Contains("="))
            {
                string[] _vals = LinkTo.Split('=');
                string lastValue = _vals[_vals.Length - 1];
                lastValue = lastValue.Substring(1, lastValue.Length - 3);
                return lastValue;
            }
            else
            {
                //Console.WriteLine();
            }
            return LinkTo;

        }
        private static string ParseDestinationParentActivity(string LinkTo)
        {
            //This might be an integer.  Someone could have pulled a functoid onto the design surface
            if (LinkTo.Contains("="))
            {
                string[] _vals = LinkTo.Split('=');
                string parentValue = _vals[_vals.Length - 2];
                parentValue = parentValue.Substring(1, parentValue.IndexOf(']') - 2);
                return parentValue;
            }
            else
            {
                Console.WriteLine();
            }
            return LinkTo;

        }
        private static string ParseSourceLink(string LinkFrom, XmlDocument doc)
        {
            string returnString = "";

            //Link is most likely something like this:
            //"/*[local-name()='&lt;Schema&gt;']/*[local-name()='WhseInvoiceDetail']/*[local-name()='ProcessingInfo']/*[local-name()='InvId']"
            //Need to convert it to
            //"/*[local-name()='&lt;Schema&gt;']/*[local-name()='WhseInvoiceDetail']/*[local-name()='ProcessingInfo']/*[local-name()='InvId']"
            int firstBracket = LinkFrom.IndexOf(']') + 1;

            //It could be a link to a functoid like this
            //<Link LinkID="10" LinkFrom="1" LinkTo="/*[local-name()='&lt;Schema&gt;']/*[local-name()='Root']/*[local-name()='Publix_GeneralMessageInfo_Rcv']/*[local-name()='ReceiveMessage']" Label="" />
            if (firstBracket == 0)
            {
                returnString = FindFunctoidInfo(LinkFrom, doc);
            }
            else
            {
                returnString = LinkFrom.Substring(firstBracket, LinkFrom.Length - firstBracket);
            }

            return returnString;

        }
        private static string ParseUploadActivityLink(string LinkFrom)
        {


            //Link is most likely something like this:
            ///*[local-name()='ContextProperties' and namespace-uri()='http://BAMWriter/v1/SystemContextProperties']/*[local-name()='CustomProperties' and namespace-uri()='']/*[local-name()='Sample_BTS_BAM_Project' and namespace-uri()='']/*[local-name()='Sample_BTS_BAM_Project.Schemas.ShowInvoice_Header_ActivityID' and namespace-uri()='']
            //Need to convert it to
            //Sample_BTS_BAM_Project.Schemas.ShowInvoice_Header_ActivityID
            string[] splitter = LinkFrom.Split('=');
            string lastNode = splitter[splitter.Length -1];
            lastNode = lastNode.Substring(1, lastNode.Length - 3);
            
            return lastNode;

        }
        
        /// <summary>
        /// This method tries to determine how to interpret the functoid reference.  The only supported mechanism is Date Time and Concatenate values
        /// </summary>
        /// <param name="LinkFrom"></param>
        /// <param name="doc"></param>
        /// <returns></returns>
        private static string FindFunctoidInfo(string LinkFrom, XmlDocument doc)
        {
            string _guid = System.Guid.NewGuid().ToString();
            Random _rand = new Random(999999999);//This is used to guarantee uniqueness
            
            XmlNodeList _nodes = doc.SelectNodes("/*[local-name()='mapsource']/*[local-name()='Pages']/*[local-name()='Page']/*[local-name()='Functoids']");
            foreach (XmlNode node in _nodes)
            {
                foreach (XmlNode childNodes in node.ChildNodes)
                {
                    if (childNodes.Attributes["FunctoidID"].InnerText == LinkFrom)
                    {
                        if (childNodes.Attributes["Functoid-Name"].InnerText == "Date and Time")
                        {
                            return "METHOD_" + _guid + ":System.DateTime.UtcNow";
                        }
                        if (childNodes.Attributes["Functoid-Name"].InnerText == "String Concatenate")
                        {
                            foreach (XmlNode inputParams in childNodes.ChildNodes)
                            {
                                foreach (XmlNode inputParam in inputParams.ChildNodes)
                                {
                                    if (inputParam.Attributes["Value"].InnerText.ToUpper().Contains("CONSTANT:"))
                                    {
                                        return "CONSTANT_" + _guid + ":" + inputParam.Attributes["Value"].InnerText;
                                    }
                                    else
                                    {
                                        return "METHOD_" + _guid + ":" + inputParam.Attributes["Value"].InnerText;
                                    }
                                }
                            }
                        }

                    }
                }
            }
            return "Unknown" + System.Guid.NewGuid().ToString(); ;
        }        
    }
}
